package com.azt.novel.config;


import com.azt.novel.common.constant.CacheConsts;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;


@Configuration
public class CacheConfig {


    /**
     * Redis 缓存管理器
     */
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {

        //设置CacheManager的值序列化方式为 fastJsonRedisSerializer,但其实RedisCacheConfiguration默认使用StringRedisSerializer序列化key，
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(
                connectionFactory);
        // 设置使用redis的一系列参数
        // RedisConnectionFactory 是创建redis连接的工厂  我们是redis的客户端（jedis -> redission）
        //  序列化方式 （决定数据以什么格式存储到redis中 以及取数据后 如何解析）
        //  默认会使用jdk的序列化方式  但实际开发会设置为其他  如 Jackson2JsonRedisSerializer
        //     创建一个序列化的对象  然后将对象放入redis的序列化容器中
        //  项目在redis存储时的前缀是什么  所有存储的key都是前缀加上key的名字  通过RedisCacheConfiguration设置
        //     将要使用的key统一管理  设置key所对应的失效时间  放到枚举类中

//        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        RedisSerializationContext.SerializationPair<Object> pair =
                RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer);

        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(pair)
                .disableCachingNullValues().prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX);

        Map<String, RedisCacheConfiguration> cacheMap = new LinkedHashMap<>(
                CacheConsts.CacheEnum.values().length);
        // 类型推断 var 非常适合 for 循环，JDK 10 引入，JDK 11 改进
        for (var c : CacheConsts.CacheEnum.values()) {
            if (c.isRemote()) {
                if (c.getTtl() > 0) {
                    cacheMap.put(c.getName(),
                            RedisCacheConfiguration.defaultCacheConfig()
                                    .serializeValuesWith(pair)
                                    .disableCachingNullValues()
                                    .prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX)
                                    .entryTtl(Duration.ofSeconds(c.getTtl())));
                } else {
                    cacheMap.put(c.getName(),
                            RedisCacheConfiguration.defaultCacheConfig()
                                    .serializeValuesWith(pair)
                                    .disableCachingNullValues()
                                    .prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX));
                }
            }
        }

        RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter,
                defaultCacheConfig, cacheMap);
        redisCacheManager.setTransactionAware(true);
        redisCacheManager.initializeCaches();
        return redisCacheManager;
    }
}
